using System;
using System.Collections;
using System.IdentityModel.Tokens.Jwt;
using System.IO;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using IServices;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using Minio.DataModel;
using Senparc.CO2NET.Extensions;
using Senparc.CO2NET.Helpers;
using Senparc.Weixin;
using Senparc.Weixin.WxOpen;
using Senparc.Weixin.WxOpen.AdvancedAPIs.Sns;
using Senparc.Weixin.WxOpen.AdvancedAPIs.WxApp;
using Senparc.Weixin.WxOpen.Entities;
using Senparc.Weixin.WxOpen.Helpers;
using SqlSugar;
using YL.Core.Dto;
using YL.Core.Entity;
using YL.NetCore.NetCoreApp;
using YL.Utils.Pub;
using YL.Utils.String;
using YL.Utils.Table;
using EncryptHelper = Senparc.Weixin.WxOpen.Helpers.EncryptHelper;

namespace EduCMS.Controllers
{
    [Route("[controller]")]
    public class WxController : BaseController
    {
        public static readonly string WxOpenAppId = PubWx.AppId;//与微信小程序后台的AppId设置保持一致，区分大小写。
        public static readonly string WxOpenAppSecret = PubWx.AppSecret;//与微信小程序账号后台的AppId设置保持一致，区分大小写。
        private readonly IWhr_wechat_sessionServices _services;
        private readonly SqlSugarClient _client;
        private readonly IWhr_user_refresh_tokenServices _userRefreshTokenServices;
        private readonly IWhr_userServices _userServices;

        public WxController(
            IWhr_wechat_sessionServices services, 
            SqlSugarClient client, 
            IWhr_user_refresh_tokenServices user_Refresh_TokenServices,
            IWhr_userServices userServices
            ) 
        {
            _services = services;
            _client = client;
            _userRefreshTokenServices = user_Refresh_TokenServices;
            _userServices = userServices;
        }
        
        /// <summary>
        /// 授权认证
        /// </summary>
        /// <param name="code"></param>
        /// <returns></returns>
        [HttpPost("authorize")]
        [AllowAnonymous]
        public JsonResult Authorize([FromForm]WechatAuthorizeDto dto) 
        {
            try
            {
                Console.WriteLine(WxOpenAppId);
                Console.WriteLine(WxOpenAppSecret);
                Console.WriteLine(dto.Code);
                var jsonResult = SnsApi.JsCode2Json(WxOpenAppId, WxOpenAppSecret, dto.Code);
                if (jsonResult.errcode == ReturnCode.请求成功)
                {
                    string wechatToken = GenerateWechatToken();
                    Whr_wechat wechat = new Whr_wechat
                    {
                        Openid = jsonResult.openid,
                        SessionKey = jsonResult.session_key,
                        WechatToken = wechatToken,
                        Platform = 2
                    };
                    _services.Set(wechat);

                    //注意：生产环境下SessionKey属于敏感信息，不能进行传输！
                    return Json(Microprogram.DataInfo(PubEnum.Success,"OK", wechatToken));
                }
                else
                {
                    return Json(Microprogram.DataInfo(PubEnum.Failed, jsonResult.errmsg + "no exception", null));
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return Json(Microprogram.DataInfo(PubEnum.Error, ex.Message, null));
            }
        }

        /// <summary>
        /// 生成微信token
        /// </summary>
        /// <returns></returns>
        private string GenerateWechatToken()
        {
            return PubId.GetUuid();
        }

        [HttpPost("bind")]
        public IActionResult BindPhoneNumber([FromForm] WechatInfoDto dto) 
        {
            var wechatToken = WechatToken();
            if (wechatToken.IsNullOrEmpty())
            {
                return Json(Microprogram.DataInfo(PubEnum.Error, "参数不齐", null));
            }

            try
            {
                var phoneNumber = DecodePhoneNumberByToken(wechatToken, dto.EncryptedData, dto.Iv);
                var mobile = phoneNumber.phoneNumber;
                var result = _userServices.RegisterAndBind(mobile, UserDto.UserId);
                if (result.Item1)
                {
                    return Json(Microprogram.DataInfo(PubEnum.Success, result.Item2, null));
                }
                else 
                {
                    return Json(Microprogram.DataInfo(PubEnum.Failed, result.Item2, null));
                }
            }
            catch (Exception ex) 
            {
                return Json(Microprogram.DataInfo(PubEnum.Failed, ex.Message, null));
            }
        }

        /// <summary>
        /// 更新用户微信基本信息
        /// </summary>
        /// <param name="wechatToken"></param>
        /// <param name="encryptedData"></param>
        /// <param name="iv"></param>
        /// <returns></returns>
        [HttpPost("info")]
        [AllowAnonymous]
        public IActionResult UpdateWechat([FromForm]WechatInfoDto dto)
        {
            string wechatToken = WechatToken();
            if (wechatToken.IsNullOrEmpty()) 
            {
                return Json(Microprogram.DataInfo(PubEnum.Error, "参数不齐", null));
            }

            DecodeEntityBase decodedEntity = DecodeUserInfoByToken(wechatToken, dto.EncryptedData, dto.Iv);

            //检验水印
            var checkWatermark = false;
            if (decodedEntity != null)
            {
                checkWatermark = decodedEntity.CheckWatermark(WxOpenAppId);

                //保存用户信息（可选）
                if (checkWatermark && decodedEntity is DecodedUserInfo decodedUserInfo)
                {
                    Whr_wechat wechat = new Whr_wechat
                    {
                        Openid = decodedUserInfo.openId,
                        Nickname = decodedUserInfo.nickName,
                        Gender = decodedUserInfo.gender,
                        City = decodedUserInfo.city,
                        Province = decodedUserInfo.province,
                        Country = decodedUserInfo.country,
                        Avatar = decodedUserInfo.avatarUrl,
                        IP = GetIp()
                    };
                    var wechatId = _services.Set(wechat);
                    var userInfo = _client.Queryable<Whr_user_wechat_rel>().Where(it => it.WechatUserId == wechatId).First();
                    var userId = 0;                   

                    if (userInfo != null)
                    {
                        userId = userInfo.UserId;
                    }
                    var cliams = new Claim[]
                    {
                        new Claim(ClaimTypes.Name, decodedUserInfo.nickName),
                        new Claim(JwtRegisteredClaimNames.Sub, wechatId.ToString()),
                        new Claim(JwtRegisteredClaimNames.Exp,  $"{new DateTimeOffset(DateTime.Now.AddHours(3)).ToUnixTimeSeconds()}"),
                        new Claim(JwtRegisteredClaimNames.Nbf, $"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}")
                    };
                    var refreshToken = StringHelper.GenerateRefreshToken();
                    _userRefreshTokenServices.CreateRefreshToken(refreshToken, wechatId);                  
                    var jwtToken = GenerateAccessToken(cliams);
                    Console.WriteLine(jwtToken);
                    Console.WriteLine(refreshToken);
                    return Json(Microprogram.DataInfo(PubEnum.Success, "获取成功", new { token = jwtToken, refresh_token = refreshToken }));
                }
            }

            if (checkWatermark)
            {
                return Json(Microprogram.DataInfo(PubEnum.Success,"OK", null));
            }
            else
            {
                return Json(Microprogram.DataInfo(PubEnum.Error,"不通过", null));
            }
        }

        private string GenerateAccessToken(Claim[] claims)
        {
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(PubConst.SecurityKey));
            var token = new JwtSecurityToken(
                    issuer: GetHost(),
                    audience: GetHost(),
                    claims: claims,
                    notBefore: DateTime.Now,
                    expires: DateTime.Now.AddHours(2),
                    signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256)
                );
            return new JwtSecurityTokenHandler().WriteToken(token);
        }

        /// <summary>
        /// 根据微信token解密微信返回加密串
        /// </summary>
        /// <param name="wechatToken"></param>
        /// <param name="encryptedData"></param>
        /// <param name="iv"></param>
        /// <returns></returns>
        /// <exception cref="WxOpenException"></exception>
        private DecodedUserInfo DecodeUserInfoByToken(string wechatToken, string encryptedData, string iv)
        {
            Whr_wechat wechat = _services.Get(wechatToken);
            if (wechat == null)
            {
                throw new WxOpenException("SessionKey无效");
            }

            string jsonStr = EncryptHelper.DecodeEncryptedData(wechat.SessionKey, encryptedData, iv);
            DecodedUserInfo entity = SerializerHelper.GetObject<DecodedUserInfo>(jsonStr);
            return entity;
        }

        private DecodedPhoneNumber DecodePhoneNumberByToken(string wechatToken, string encryptData, string iv) 
        {
            Whr_wechat wechat = _services.Get(wechatToken);
            if (wechat == null)
            {
                throw new WxOpenException("wechatToken无效");
            }
            var phoneNumber = EncryptHelper.DecryptPhoneNumber(wechat.SessionKey, encryptData, iv);
            return phoneNumber;
        }
        
        /// <summary>
        /// 获取二维码
        /// </summary>
        /// <param name="useBase64"></param>
        /// <param name="codeType"></param>
        /// <returns></returns>
        [HttpGet("qrcode/{useBase64}/{codeType}")]
        [AllowAnonymous]
        public async Task<IActionResult> GetQrCode(string useBase64 = null, string codeType = "2")
        {
            string wechatToken = WechatToken();
            Whr_wechat whrWechat = _services.Get(wechatToken);
            if (whrWechat == null)
            {
                return Json(Microprogram.DataInfo(PubEnum.Error,"请先微信授权！", null));
            }

            var ms = new MemoryStream();
            var openId = whrWechat.Openid;
            var page = "pages/QrCode/QrCode";//此接口不可以带参数，如果需要加参数，必须加到scene中
            var scene = $"OpenIdSuffix:{openId.Substring(openId.Length - 10, 10)}#{codeType}";//储存OpenId后缀，以及codeType。scene最多允许32个字符
            LineColor lineColor = null;//线条颜色
            if (codeType == "2")
            {
                lineColor = new LineColor(221, 51, 238);
            }

            var result = await WxAppApi.GetWxaCodeUnlimitAsync(WxOpenAppId, ms, scene, page, lineColor: lineColor);
            ms.Position = 0;

            if (!useBase64.IsNullOrEmpty())
            {
                //转base64
                var imgBase64 = Convert.ToBase64String(ms.GetBuffer());
                return Json(Microprogram.DataInfo(PubEnum.Success,"ok", imgBase64));
            }
            else
            {
                //返回文件流
                return File(ms, "image/jpeg");
            }
        }

        /// <summary>
        /// 用户微信token
        /// </summary>
        /// <returns></returns>
        private string WechatToken()
        {
            return HttpContext.Request.Headers["Wechat-Token"].ToString();
        }
    }
}